package com.blog.lucene;

import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Paths;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import com.blog.entity.Blog;
import com.blog.util.DateUtil;
import com.blog.util.StringUtil;


public class BlogIndex {

	private Directory directory;
	
	private IndexWriter getWriter() throws IOException {
		directory =FSDirectory.open(Paths.get("F://lucene"));
		SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();
		IndexWriterConfig iwc=new IndexWriterConfig(analyzer);
		IndexWriter writer=new IndexWriter(directory, iwc);
		return writer;
		
	}
	
	public void addIndex(Blog blog) throws IOException {
		IndexWriter writer=getWriter();
		Document document=new Document();
		document.add(new StringField("id", String.valueOf(blog.getId()),Field.Store.YES));
		document.add(new TextField("title", blog.getTitle(),Field.Store.YES));
		document.add(new StringField("releaseDate", DateUtil.formatDate(new Date(), "yyyy-MM-dd"),Field.Store.YES));
		document.add(new TextField("content", blog.getContentNoTag(),Field.Store.YES));
		writer.addDocument(document);
		writer.close();
	}
	
	public void deleteIndex(String blogId) throws IOException {
		IndexWriter writer=getWriter();
		writer.deleteDocuments(new Term("id", blogId));
		writer.forceMergeDeletes();
		writer.commit();
		writer.close();
	}
	
	public void updateIndex(Blog blog) throws IOException {
		IndexWriter writer=getWriter();
		Document document=new Document();
		document.add(new StringField("id", String.valueOf(blog.getId()),Field.Store.YES));
		document.add(new TextField("title", blog.getTitle(),Field.Store.YES));
		document.add(new StringField("releaseDate", DateUtil.formatDate(new Date(), "yyyy-MM-dd"),Field.Store.YES));
		document.add(new TextField("content", blog.getContentNoTag(),Field.Store.YES));
		writer.updateDocument(new Term("id", String.valueOf(blog.getId())), document);
		writer.close();
	}
	
	public List<Blog> searchBlog(String keyword) throws IOException, ParseException, InvalidTokenOffsetsException{
		directory=FSDirectory.open(Paths.get("F://lucene"));
		IndexReader reader=DirectoryReader.open(directory);
		IndexSearcher indexSearcher=new IndexSearcher(reader);
		BooleanQuery.Builder booleanQuery=new BooleanQuery.Builder();
		SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();
		QueryParser parser=new QueryParser("title", analyzer);
		Query query=parser.parse(keyword);
		
		QueryParser parser2=new QueryParser("content",analyzer);
		Query query2=parser2.parse(keyword);
		
		booleanQuery.add(query,BooleanClause.Occur.SHOULD);
		booleanQuery.add(query2, BooleanClause.Occur.SHOULD);
		
		TopDocs hits=indexSearcher.search(booleanQuery.build(),100);
		QueryScorer scorer=new QueryScorer(query);
		Fragmenter fragmenter=new SimpleSpanFragmenter(scorer);
		SimpleHTMLFormatter simpleHTMLFormatter=new SimpleHTMLFormatter("<b><font color='red'>","</font></b>");
		Highlighter highlighter=new Highlighter(simpleHTMLFormatter,scorer);
		highlighter.setTextFragmenter(fragmenter);
		
		List<Blog> blogList=new LinkedList<Blog>();
		for(ScoreDoc scoreDoc:hits.scoreDocs) {
			Document document=indexSearcher.doc(scoreDoc.doc);
			Blog blog=new Blog();
			blog.setId(Integer.parseInt(document.get("id")));
			blog.setReleaseDateStr(document.get("releaseDate"));
			String title=document.get("title");
			String content=StringEscapeUtils.escapeHtml(document.get("content"));
			if (title!=null) {
				TokenStream tokenStream=analyzer.tokenStream("title", new StringReader(title));
				String hTitle=highlighter.getBestFragment(tokenStream, title);
				if (StringUtil.isEmpty(hTitle)) {
					blog.setTitle(title);
				}else {
					blog.setTitle(hTitle);
				}
			}
			if (content!=null) {
				TokenStream tokenStream=analyzer.tokenStream("content", new StringReader(content));
				String hContent=highlighter.getBestFragment(tokenStream, content);
				if (StringUtil.isEmpty(hContent)) {
					
					if (content.length()<=200) {
						blog.setContent(content);
					}else {
						blog.setContent(content.substring(0, 200));
					}
				}else {
					blog.setContent(hContent);
				}
			}
			blogList.add(blog);
		}
		return blogList;
		
	}
}
